/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "pin_auth_ipc_proxy.h"

#include <securec.h>
#include <stddef.h>

#include "logger.h"

ResultCode SePinEnrollLocalProxy(IpcTransmit *transmit, uint32_t slotId, const PinDataHash *hash, PinDataSecret *secret)
{
    if (transmit == NULL || hash == NULL || secret == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    PinEnrollLocalInput input;
    (void)memset_s(&input, sizeof(PinEnrollLocalInput), 0, sizeof(PinEnrollLocalInput));
    input.slotId = slotId;
    input.hash = *hash;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(PinEnrollLocalInput);

    uint8_t *reply = (uint8_t *)secret;
    uint32_t replyLen = sizeof(PinDataSecret);
    return transmit(CMD_PIN_AUTH_ENROLL_LOCAL, data, dataLen, reply, &replyLen);
}

ResultCode SePinAuthLocalProxy(IpcTransmit *transmit, uint32_t slotId, const PinDataHash *hash, PinAuthResult *result)
{
    if (transmit == NULL || hash == NULL || result == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    PinAuthLocalInput input;
    (void)memset_s(&input, sizeof(PinAuthLocalInput), 0, sizeof(PinAuthLocalInput));
    input.slotId = slotId;
    input.hash = *hash;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(PinAuthLocalInput);

    uint8_t *reply = (uint8_t *)result;
    uint32_t replyLen = sizeof(PinAuthResult);

    return transmit(CMD_PIN_AUTH_AUTHENTICATION_LOCAL, data, dataLen, reply, &replyLen);
}

ResultCode SePinEnrollRemoteProxy(IpcTransmit *transmit, uint32_t slotId, const PinDataRemoteBase *base)
{
    if (transmit == NULL || base == NULL) {
        return INVALID_PARA_NULL_PTR;
    }
    PinEnrollRemoteInput input;
    (void)memset_s(&input, sizeof(PinEnrollRemoteInput), 0, sizeof(PinEnrollRemoteInput));
    input.slotId = slotId;
    input.base = *base;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(PinEnrollRemoteInput);

    return transmit(CMD_PIN_AUTH_ENROLL_REMOTE, data, dataLen, NULL, NULL);
}

ResultCode SePinAuthRemotePrepareProxy(IpcTransmit *transmit, uint32_t slotId, uint64_t session,
    PinDataRemoteServiceChallenge *challenge)
{
    if (transmit == NULL || challenge == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    PinAuthRemotePrepareInput input = {.slotId = slotId, .session = session};

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(input);

    PinDataRemoteServiceChallenge output;
    (void)memset_s(&output, sizeof(output), 0, sizeof(output));

    uint8_t *reply = (uint8_t *)&output;
    uint32_t replyLen = sizeof(output);

    ResultCode ret = transmit(CMD_PIN_AUTH_AUTHENTICATION_REMOTE_PREPARE, data, dataLen, reply, &replyLen);
    if (ret != SUCCESS) {
        return ret;
    }

    *challenge = output;
    return SUCCESS;
}

ResultCode SePinAuthRemoteProxy(IpcTransmit *transmit, uint32_t slotId, uint64_t session,
    const PinDataRemoteClientProof *proof, PinAuthResult *result)
{
    if (transmit == NULL || proof == NULL || result == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    PinAuthRemoteInput input;
    (void)memset_s(&input, sizeof(input), 0, sizeof(input));
    input.slotId = slotId;
    input.session = session;
    input.proof = *proof;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(input);

    uint8_t *reply = (uint8_t *)result;
    uint32_t replyLen = sizeof(PinAuthResult);

    return transmit(CMD_PIN_AUTH_AUTHENTICATION_REMOTE, data, dataLen, reply, &replyLen);
}

ResultCode SePinAuthRemoteAbortProxy(IpcTransmit *transmit, uint32_t slotId, uint64_t session)
{
    if (transmit == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    PinAuthRemoteAbortInput input;
    (void)memset_s(&input, sizeof(input), 0, sizeof(input));
    input.slotId = slotId;
    input.session = session;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(input);

    return transmit(CMD_PIN_AUTH_AUTHENTICATION_REMOTE_ABORT, data, dataLen, NULL, NULL);
}

ResultCode SePinSetSelfDestructEnableProxy(IpcTransmit *transmit, uint32_t slotId, const PinDestructConfig *config,
    const PinDataHash *hash, PinConfigResult *configResult)
{
    if (transmit == NULL || config == NULL || hash == NULL || configResult == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    SetSelfDestructEnableInput input;
    (void)memset_s(&input, sizeof(SetSelfDestructEnableInput), 0, sizeof(SetSelfDestructEnableInput));
    input.slotId = slotId;
    input.enable = config->enable ? 1 : 0;
    input.destructMaxCnt = config->destructMaxCnt;
    input.hash = *hash;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(SetSelfDestructEnableInput);

    uint8_t *reply = (uint8_t *)configResult;
    uint32_t replyLen = sizeof(PinConfigResult);

    return transmit(CMD_PIN_AUTH_CONFIG_SELF_DESTRUCT, data, dataLen, reply, &replyLen);
}

ResultCode SePinGetNumSlotsProxy(IpcTransmit *transmit, uint32_t *numSlots)
{
    if (transmit == NULL || numSlots == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t *reply = (uint8_t *)numSlots;
    uint32_t replyLen = sizeof(uint32_t);

    return transmit(CMD_PIN_AUTH_GET_SLOT_NUM, NULL, 0, reply, &replyLen);
}

ResultCode SePinGetFreezeStatusProxy(IpcTransmit *transmit, uint32_t slotId, PinFreezeStatus *pinFreezeStatus)
{
    if (transmit == NULL || pinFreezeStatus == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    const uint8_t *data = (const uint8_t *)&slotId;
    uint32_t dataLen = sizeof(slotId);

    uint8_t *reply = (uint8_t *)pinFreezeStatus;
    uint32_t replyLen = sizeof(PinFreezeStatus);
    return transmit(CMD_PIN_AUTH_GET_SLOT_STATUS, data, dataLen, reply, &replyLen);
}

ResultCode SePinSetFreezePolicyProxy(IpcTransmit *transmit, uint16_t punishStartCnt, uint16_t destructMaxCnt,
    uint32_t enableDestructDefault)
{
    if (transmit == NULL) {
        return INVALID_PARA_NULL_PTR;
    }
    SetFreezePolicyInput input;
    (void)memset_s(&input, sizeof(SetFreezePolicyInput), 0, sizeof(SetFreezePolicyInput));
    input.punishStartCnt = punishStartCnt;
    input.destructMaxCnt = destructMaxCnt;
    input.enableDestructDefault = enableDestructDefault;

    const uint8_t *data = (const uint8_t *)&input;
    uint32_t dataLen = sizeof(SetFreezePolicyInput);
    return transmit(CMD_PIN_AUTH_CONFIG_FREEZE_POLICY, data, dataLen, NULL, NULL);
}

ResultCode SePinGetFreezePolicyProxy(IpcTransmit *transmit, uint16_t *punishStartCnt, uint16_t *destructMaxCnt,
    uint32_t *enableDestructDefault)
{
    if (transmit == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    if (punishStartCnt == NULL || destructMaxCnt == NULL || enableDestructDefault == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    GetFreezePolicyOutput output;
    (void)memset_s(&output, sizeof(GetFreezePolicyOutput), 0, sizeof(GetFreezePolicyOutput));

    uint8_t *reply = (uint8_t *)&output;
    uint32_t replyLen = sizeof(output);

    ResultCode ret = transmit(CMD_PIN_AUTH_GET_FREEZE_POLICY, NULL, 0, reply, &replyLen);
    if (ret != SUCCESS) {
        return ret;
    }
    *punishStartCnt = output.punishStartCnt;
    *destructMaxCnt = output.destructMaxCnt;
    *enableDestructDefault = output.enableDestructDefault;
    return SUCCESS;
}

ResultCode SePinEraseSingleSlotProxy(IpcTransmit *transmit, uint32_t slotId)
{
    if (transmit == NULL) {
        return INVALID_PARA_NULL_PTR;
    }
    const uint8_t *data = (const uint8_t *)&slotId;
    uint32_t dataLen = sizeof(slotId);

    return transmit(CMD_PIN_AUTH_ERASE_SINGLE_SLOT, data, dataLen, NULL, NULL);
}

ResultCode SePinEraseAllSlotsProxy(IpcTransmit *transmit)
{
    if (transmit == NULL) {
        return INVALID_PARA_NULL_PTR;
    }
    return transmit(CMD_PIN_AUTH_ERASE_ALL_SLOTS, NULL, 0, NULL, NULL);
}